﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Globalization;

namespace StatusPlan3
{
    public enum LogLevel : int
    {
        Error = 1,
        ErrorsAndMessages = 2,
        Everything = 3
    }

    public class Logger
    {
        private static string startupLogEntryData = string.Empty;
        internal static DateTime LastLoggedDate = new DateTime(1, 1, 1);
        public static int FileLogLevel = 3;

        /// <summary>
        /// Gets or sets the startup log value.
        /// </summary>
        /// <value>The startup log value.</value>
        public static string StartupLogEntryData
        {
            get
            {
                return startupLogEntryData;
            }
            set
            {
                startupLogEntryData = value;
            }
        }

        public static void Log(string message)
        {
            Log(message, LogLevel.Everything);
        }

        public static void Log(string message, int MaxLength)
        {
            if (message.Length > MaxLength)
                message = message.Remove(MaxLength) + "... (truncated)";
            Log(message, LogLevel.Everything);
        }

        /// <summary>
        /// Logs the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="level">The level.</param>
        public static void Log(string message, LogLevel level)
        {
            if (FileLogLevel >= (int)level)
            {
                LogToFile(message);
            }
        }


        /// <summary>
        /// Logs the specified exception
        /// </summary>
        /// <param name="ex">The ex.</param>
        /// <param name="parameterValues">The parameter values.</param>
        public static void Log(Exception ex, params string[] parameterValues)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(ex.Message + Environment.NewLine + ex.StackTrace);
            if (parameterValues != null && parameterValues.Length > 0)
            {
                builder.Append("Params : " + Environment.NewLine);
                foreach (string value in parameterValues)
                {
                    builder.Append(value + Environment.NewLine);
                }
            }
            GetInnerExceptionMessages(ex, ref builder);
            LogToFile(builder.ToString());
        }

        public static void Log(string Message, params object[] parameterValues)
        {
            try
            {
                Log(string.Format(Message, parameterValues));
            }
            catch (Exception Ex)
            {
                Log("Exception in Log(string Message, params string[] parameterValues). E: " + Ex.Message);
            }


        }


        /// <summary>
        /// Gets the inner exception messages.
        /// </summary>
        /// <param name="ex">The ex.</param>
        /// <param name="builder">The builder.</param>
        private static void GetInnerExceptionMessages(Exception ex, ref StringBuilder builder)
        {
            if (ex.InnerException != null)
            {
                builder.Append(ex.InnerException.Message);
                GetInnerExceptionMessages(ex.InnerException, ref builder);
            }
        }


        /// <summary>
        /// Determines whether the log file is valid.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if [is log file valid]; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsLogFileValid()
        {
            FileStream fs = null;
            try
            {
                string startupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                string logFileName = startupPath + @"\Logs\log" + DateTime.Now.Day + ".log";
                
                if (!System.IO.File.Exists(logFileName))
                {
                    return false;
                }

                fs = new FileStream(logFileName, FileMode.Open, FileAccess.Read);
                StreamReader reader = new StreamReader(fs);
                string firstLine = reader.ReadLine();
                DateTime dt = DateTime.Parse(firstLine);

                if (dt.Day != DateTime.Now.Day || dt.Month != DateTime.Now.Month || dt.Year != DateTime.Now.Year)
                {
                    return false;
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// Logs to file.
        /// </summary>
        /// <param name="message">The message.</param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        private static void LogToFile(string message)
        {
            FileStream fs = null;
            try
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
                Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

                bool isNewLogFile = false;
                string startupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

                if (!Directory.Exists(startupPath + @"\Logs\"))
                {
                    Directory.CreateDirectory(startupPath + @"\Logs\");
                }

                string filePath = startupPath + @"\Logs\log" + DateTime.Now.Day + ".log";
                bool isValidFile;

                if (LastLoggedDate.Day == 1 && LastLoggedDate.Month == 1 && LastLoggedDate.Year == 1)
                {
                    isValidFile = IsLogFileValid();
                }
                else if (LastLoggedDate.Day == DateTime.Now.Day && LastLoggedDate.Month == DateTime.Now.Month && LastLoggedDate.Year == DateTime.Now.Year)
                {
                    isValidFile = true;
                }
                else
                {
                    isValidFile = false;
                }

                if (isValidFile)
                {
                    fs = new FileStream(filePath, FileMode.Append, FileAccess.Write);
                }
                else
                {
                    //extra check
                    if (System.IO.File.Exists(filePath))
                    {
                        fs = new FileStream(filePath, FileMode.Truncate, FileAccess.Write);
                    }
                    else
                    {
                        fs = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
                    }

                    isNewLogFile = true;
                }

                StreamWriter sw = new StreamWriter(fs);

                if (isNewLogFile)
                {
                    sw.WriteLine(DateTime.Now.ToShortDateString());
                    sw.WriteLine(Logger.StartupLogEntryData);
                }

                sw.WriteLine(GetFormattedTime() + " " + message);
                sw.Flush();

                LastLoggedDate = DateTime.Now;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }



        /// <summary>
        /// Gets the formatted time.
        /// </summary>
        /// <returns></returns>
        private static string GetFormattedTime()
        {
            StringBuilder builder = new StringBuilder();
            if (DateTime.Now.Hour.ToString().Length == 1)
            {
                builder.Append("0" + DateTime.Now.Hour.ToString() + ".");
            }
            else
            {
                builder.Append(DateTime.Now.Hour.ToString() + ".");
            }



            if (DateTime.Now.Minute.ToString().Length == 1)
            {
                builder.Append("0" + DateTime.Now.Minute.ToString() + ".");
            }
            else
            {
                builder.Append(DateTime.Now.Minute.ToString() + ".");
            }



            if (DateTime.Now.Second.ToString().Length == 1)
            {
                builder.Append("0" + DateTime.Now.Second.ToString());
            }
            else
            {
                builder.Append(DateTime.Now.Second.ToString());
            }

            return builder.ToString();
        }

    }
}
